package cn.assumejson.springframework.aop.aspectj.annotation;

import cn.assumejson.springframework.aop.Advisor;
import cn.assumejson.springframework.beans.factory.ListableBeanFactory;
import cn.assumejson.springframework.beans.factory.support.DefaultListableBeanFactory;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import org.aspectj.lang.annotation.Aspect;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 从工厂中回去需要AOP的Bean
 *
 * @author gang.Li
 * @version 1.0
 * @since 1.0 2021/12/9 14:16
 */
public class BeanFactoryAspectJAdvisorsBuilder {

    private final ListableBeanFactory beanFactory;

    private final AspectJAdvisorFactory advisorFactory;

    private volatile List<String> aspectBeanNames;

    private final Map<String, List<Advisor>> advisorsCache = new ConcurrentHashMap<>();

    public BeanFactoryAspectJAdvisorsBuilder(ListableBeanFactory beanFactory, AspectJAdvisorFactory advisorFactory) {
        Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
        Assert.notNull(advisorFactory, "AspectJAdvisorFactory must not be null");
        this.beanFactory = beanFactory;
        this.advisorFactory = advisorFactory;
    }

    public List buildAspectJAdvisors() {
        // 获取所有的Aspect
        List<String> aspectNames = this.aspectBeanNames;

        if (CollUtil.isEmpty(aspectNames)) {
            synchronized (this) {
                aspectNames = this.aspectBeanNames;
                if (CollUtil.isEmpty(aspectNames)) {
                    List<Advisor> advisors = new ArrayList<>();
                    aspectNames = new ArrayList<>();

                    // 获取所有的BeanName
                    String[] beanNames = this.beanFactory.getBeanNamesForType(Object.class, true, false);
                    for (String beanName : beanNames) {
                        if (!isEligibleBean(beanName)) {
                            continue;
                        }
                        Class<?> beanType = ((DefaultListableBeanFactory) this.beanFactory).getBeanDefinition(beanName).getBeanClass();
                        if (beanType == null) {
                            continue;
                        }
                        if (ObjectUtil.isNotNull(beanType.getAnnotation(Aspect.class))) {
                            // 切面
                            // 保存切面信息
                            aspectNames.add(beanName);

                            // 解析切面
                            BeanFactoryAspectInstanceFactory factory =
                                    new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);

                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            // 缓存切面所对应的所有Advisor对象
                            this.advisorsCache.put(beanName, classAdvisors);
                            advisors.addAll(classAdvisors);

                        }
                    }
                    this.aspectBeanNames = aspectNames;
                    return advisors;
                }
            }
        }

        if (aspectNames.isEmpty()) {
            return Collections.EMPTY_LIST;
        }
        // 如果切面已经找到过了，那么则遍历每个切面是否缓存了对应的Advisor，如果没有缓存则进行解析得到Advisor
        List<Advisor> advisors = new ArrayList<>();
        for (String aspectName : aspectNames) {
            List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
            if (cachedAdvisors != null) {
                advisors.addAll(cachedAdvisors);
            } else {
                advisors.addAll(this.advisorFactory.getAdvisors(new BeanFactoryAspectInstanceFactory(this.beanFactory, aspectName)));
            }
        }
        return advisors;
    }

    protected boolean isEligibleBean(String beanName) {
        return true;
    }
}
